#include "Report.h"
#include "ReportSystemExceptions.h"
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
string Report::GetTextTemplate() const
{
	return textTemplate;
}
string Report::GetReport() const
{
	return reportText;
}
bool Report::SaveReport(const string& outputFile) const
{
	// Method saves the ready report into user-defined file
	ofstream outStream(outputFile);
	if (! outStream)
	{
		return false;
	}
	outStream << reportText;
	outStream.close();
	return true;
}
Report::Report(const string& fileParamsPath, const string& txtTmpl)
{
	// Reads the file with parameters and fills the container
	// of parameters. Gets the report sample.
	textTemplate = txtTmpl;
	ifstream in(fileParamsPath);
	if (! in)
	{
		cout << "Cannot open file with parameters, program is terminating." << endl;
		cin.get();
		exit(-1);
	}
	string key = "", value = "", type = "";
	while(in)
	{
		getline(in, key, '=');
		getline(in, value, '\n');
		getline(in, type, '\n');
		in.get(); // get the dividing empty line
		CommonParamValue *paramValue = CreateParamValue(type);
		paramValue->SetValue(value);
		params.insert(make_pair(key, paramValue));
	}
	in.close();
}
Report::~Report()
{
	// Deletes all dynamic objects of CommonParamValue type and clears
	// the container with parameters
	for (paramsIter = params.begin(); paramsIter != params.end(); paramsIter++)
	{
		delete paramsIter->second;
	}
	params.clear();
}
void Report::GenerateReport()
{
	// Sets the "reportText" member using
	// report template - "textTemplate"
	// and container with parameters - "params"
	string workingText = textTemplate;
	string paramText, paramKey;		// paramText sample: {*paramKey}
		// paramKey is a parameter key without {, *, }
	size_t readyTextPos;
		// readyTextPos divides the processed and unprocessed text
	size_t posOfRightDelimiter;
	size_t posOfLeftDelimiter = workingText.find_first_of(LEFT_DELIMITER);
	while(posOfLeftDelimiter != string::npos)
	{
		posOfRightDelimiter = workingText.find_first_of(RIGHT_DELIMITER);
		paramText = workingText.substr(posOfLeftDelimiter, posOfRightDelimiter-posOfLeftDelimiter+1);
		paramKey = paramText.substr(1, (paramText.length() - 2));
		paramsIter = params.find(paramKey);
		if (paramsIter != params.end())
		{
			if( ("" == paramsIter->second->GetValue()) &&
				(paramKey[0] == '*') )
			{
				// the necessary parameter is empty - exception
				readyTextPos = posOfRightDelimiter+1;
				string message = '\n' + "The necessary parameter " + paramKey + " is empty!" + '\n';
				ExitProgram status = NO;
				throw ReportSystemExceptions(message, status);
			}
			else
			{
				// parameter is found in container and has a non-empty value
				workingText.replace(posOfLeftDelimiter,
					posOfRightDelimiter-posOfLeftDelimiter+1,
					paramsIter->second->GetValue());
				readyTextPos = posOfLeftDelimiter + paramsIter->second->GetValue().length();
			}
		}
		else
		{
			// non-existent parameter - error
			cout << "Parameter " << paramKey << " does not exist!" << endl;
			readyTextPos = posOfRightDelimiter+1;
		}
		reportText += workingText.substr(0, readyTextPos);
			// copy the processed text to final text
		workingText = workingText.substr(readyTextPos, workingText.size());
			// truncate the processed text from working string
		posOfLeftDelimiter = workingText.find_first_of(LEFT_DELIMITER);
			// find the next left delimiter for further iteration
	}
	reportText += workingText;
		// copy the rest of text without parameters to the final text
}
CommonParamValue* Report::CreateParamValue(const string &strType) const
{
	if (strType == "int")
	{
		return (new IntParamValue());
	}
	else if(strType == "double")
	{
		return (new DoubleParamValue());
	}
	else if(strType == "timeFunction")
	{
		return (new CurTimeParamValue());
	}
	else if(strType == "string")
	{
		return (new StringParamValue());
	}
	else
	{
		// error - exception
		string message = "Non-existent type of parameter is found." + '\n';
		ExitProgram status = YES;
		throw ReportSystemExceptions(message, status);
	}
}